import { updateNodeElement } from "../DOM"
import { createTaskQueue, arrified, createStateNode, getTag, getRoot } from "../misc"

const taskQueue  = createTaskQueue()
let subTask = null

let pendingCommit = null

const commitAllWork = fiber => {
  fiber.effects.forEach(item => {

    if(item.tag === 'class_component') {
      item.stateNode.__fiber = item
    }

    if(item.effectTag === 'delete') {
      item.parent.stateNode.removeChild(item.stateNode)
    } else if(item.effectTag === 'update') {
      if(item.type === item.alternate.type) {
        // 节点类型相同
        updateNodeElement(item.stateNode, item, item.alternate)
      } else {
        item.parent.stateNode.replaceChild(item.stateNode, item.alternate.stateNode)
      }
    } else if(item.effectTag === 'placement') {
      let fiber = item
      let parentFiber = item.parent
      while(parentFiber.tag === 'class_component' || 
        parentFiber.tag === 'function_component'
      ) {
        parentFiber = parentFiber.parent
      }
      if(fiber.tag === 'host_component') {
        fiber.parent.stateNode.appendChild(fiber.stateNode)
      }  
    }
  })
  // 备份旧的 fiber 对线
  fiber.stateNode.__rootFiberContainer = fiber
}

const getFirstTask = () => {
  // 从任务队列中获取任务
  const task = taskQueue.pop()

  if(task.from === 'class_component') {
    // 组件状态更新
    const root = getRoot(task.instance)    
    task.instance.__fiber.partialState = task.partialState
    return {
      props: task.props,
      stateNode: root.stateNode,
      tag: 'host_root',
      effects: [],
      child: null,
      alternate: root
    }
  }

  // 返回最外层节点的fiber对象
  return {
    props: task.props,
    stateNode: task.dom,
    tag: 'host_root',
    effects: [],
    child: null,
    alternate: task.dom.__rootFiberContainer
  }
}

const reconcileChildren = (fiber, children) => {
  // children 可能是对象，也可能是数组，将children转换成数组
  const arrifiedChildren = arrified(children)

  let index = 0
  let numberOfElement = arrifiedChildren.length
  let element = null
  let newFiber = null
  let prevFiber = null

  let alternate = null

  // 先取出fiber对象之前的备份
  if(fiber.alternate && fiber.alternate.child) {
    alternate = fiber.alternate.child
  }

  while(index < numberOfElement || alternate) {
    // 子级 virtualDOM 对象
    element = arrifiedChildren[index]

    if(!element && alternate) {
      // 删除
      alternate.effectTag = 'delete'
      fiber.effects.push(alternate)
    } else if(element && alternate) {
      // 更新
      newFiber = {
        type: element.type,
        props: element.props,
        tag: getTag(element),
        effects: [],
        effectTag: 'update',
        parent: fiber,
        alternate
      }

      if(element.type === alternate.type) {
        // 类型相同
        newFiber.stateNode = alternate.stateNode
      } else {
        newFiber.stateNode = createStateNode(newFiber)
      }
    } else if(element && !alternate) {
      // 初始渲染
      newFiber = {
        type: element.type,
        props: element.props,
        tag: getTag(element),
        effects: [],
        effectTag: 'placement',
        parent: fiber
      }
  
      newFiber.stateNode = createStateNode(newFiber)
    }

    if(index === 0) {
      fiber.child = newFiber
    } else if(element) {
      prevFiber.sibling = newFiber
    }

    if(alternate && alternate.sibling) {
      alternate = alternate.sibling
    } else {
      alternate = null
    }

    prevFiber = newFiber
    
    index++
  }
}

const executeTask = fiber => {
  if(fiber.tag === 'class_component') {
    if(fiber.stateNode.__fiber && fiber.stateNode.__fiber.partialState) {
      fiber.stateNode.state = {
        ...fiber.stateNode.state,
        ...fiber.stateNode.__fiber.partialState
      }
    }

    reconcileChildren(fiber, fiber.stateNode.render())
  } else if (fiber.tag === 'function_component') {
    reconcileChildren(fiber, fiber.stateNode(fiber.props))
  } else {
    reconcileChildren(fiber, fiber.props.children)
  }
  
  if(fiber.child) {
    return fiber.child
  }
  let currentExecutelyFiber = fiber
  while(currentExecutelyFiber.parent) {
    currentExecutelyFiber.parent.effects = currentExecutelyFiber.parent.effects.concat(
      currentExecutelyFiber.effects.concat([currentExecutelyFiber])
    )
    if(currentExecutelyFiber.sibling) {
      return currentExecutelyFiber.sibling
    }
    currentExecutelyFiber = currentExecutelyFiber.parent
  }

  pendingCommit = currentExecutelyFiber
}

const workLoop = deadLine => {
  if(!subTask) {
    subTask = getFirstTask()
  }

  // 第一阶段，diff运算
  while(subTask && deadLine.timeRemaining() > 1) {
    subTask = executeTask(subTask)
  }

  // 第二阶段，渲染DOM
  if(pendingCommit) {
    commitAllWork(pendingCommit)
  }
}

const performTask = deadLine => {
  workLoop(deadLine)

  if(subTask || !taskQueue.isEmpty()) {
    requestIdleCallback(performTask)
  }
}

export const render = (element, dom) => {
  /*
    1.向任务队列添加任务
      任务就是通过 vdom 对象构建 fiber对象
    2.指定在浏览器空闲时执行任务
  */

  taskQueue.push({
    dom,
    props: { children: element }
  })

  requestIdleCallback(performTask)
}

export const scheduleUpdate = (instance, partialState) => {
  taskQueue.push({
    from: 'class_component',
    instance,
    partialState
  })

  requestIdleCallback(performTask)
}